#include "base.h"
#include "type.h"
#include "proc.h"
#include "protect.h"
#include "kparam.h"

#include "string.h"

PUBLIC struct proc proc[PROC_NUM] = {[0 ... (PROC_NUM - 1)].pid = INVALID};
PUBLIC struct proc *proc_queue_h[PRIV_MAX];		/* different privilege process queues, used for scheduling */
PUBLIC struct proc *proc_queue_t[PRIV_MAX];		/* different privilege process queues, used for scheduling */
PUBLIC struct proc *proc_suspend_queue;
PUBLIC struct proc *cur_proc ;

int tss_switch(void){
	tss.esp0 = K_STACK;
	
	return 0;
}

#if 0
/*
 * enqueue the new process to the brother queue 
 */
int proc_enbrotherq(struct proc *father, struct proc *new_child){
	struct proc *child = father->child;

	if (child == NULL){
		father->child = new_child;
	}else{
		while(TRUE){
			if (child->brother == NULL){
				child->brother = new_child;
				break;
			}else{
				child = child->brother;
			}
		}
	}
	return 0;
}
#endif

int proc_en_suspend_queue(struct proc *proc_p){
	struct proc *suspend_p = proc_suspend_queue;
	if (!proc_p){
		return 0;
	}

	if (!suspend_p){
		suspend_p = proc_p;
		return 0;
	}

	while(TRUE){
		if (!suspend_p->next){
			suspend_p->next = proc_p;
			break;
		}

		suspend_p = suspend_p->next;
	}
	return 0;	
}

int proc_de_suspend_queue(struct proc *proc_p){
	struct proc *suspend_p = proc_suspend_queue;
	if (!proc_p){
		return 0;
	}

	if (!suspend_p){
		return 0;
	}

	while(TRUE){
		if (suspend_p->next == proc_p){
			suspend_p->next = proc_p->next;
			proc_p->next = NULL;
			break;
		}

		suspend_p = suspend_p->next;
	}
	
	return 0;	
}

int proc_en_ready_queue(struct proc *proc_p){
	int priv = proc_p->priv;

	if (!proc_p){
		return 0;
	}

	if (proc_queue_h[priv] == NULL){
		proc_queue_h[priv] = proc_p;
		proc_queue_t[priv] = proc_p;
	}else{
		proc_queue_t[priv]->next = proc_p;
		proc_queue_t[priv] = proc_p;
	}
	return 0;
}


int proc_de_ready_queue(struct proc *de_proc){
	struct proc *proc_p = NULL;
	int priv = de_proc->priv;

	if (!proc_p){
		return 0;
	}
	
	if (proc_queue_h[priv] == NULL){
		return 0;
	}

	for (proc_p = proc_queue_h[priv]; ; proc_p = proc_p->next){
		if ((proc_p)&&(proc_p->next == de_proc)) {
			proc_p->next = de_proc->next ;
			de_proc->next = NULL;
		}
	}

	return 0;
}

static uint_32 pid_max = 0;

static int proc_alloc(struct proc **new_proc){
	int pid_max_temp = pid_max;
	
	while(TRUE){
		pid_max_temp ++;
		pid_max_temp %= PROC_NUM;
		if (proc[pid_max_temp].pid == INVALID){
			proc[pid_max_temp].pid = pid_max = pid_max_temp;
			*new_proc = &(proc[pid_max_temp]);
			break;
		}else if(pid_max_temp == pid_max){
			*new_proc = NULL;
			break;
		}else{
			/* loop again */
		}
	}
	return 0;
}

int proc_destroy_relation(struct proc *del_proc){
	return 0;
}

int proc_remake_relation(){
	return 0;
}

int proc_free(struct proc **del_proc){
	proc_remake_relation(*del_proc);
	proc_de_ready_queue(*del_proc);
	memset((int_8 *)(*del_proc),NULL,sizeof(struct proc));
	(*del_proc)->pid = INVALID;
	*del_proc = NULL;
	del_proc = NULL;
	return 0;
}

struct proc* proc_new(void){
	struct proc *new_proc;

	proc_alloc(&new_proc);

	return new_proc;
}

int proc_update_status(struct proc *proc_p,int status){
	return 0;
}

struct proc* server_proc_pick(int priv){
	struct proc *pick_proc = NULL;

	/* avoid warning */
	priv = priv;

	/* though server processes are always runable, */
	/* only when one of them received some request, it could be chose. */
	/* Otherwise continue to check the rest process in queue */
	for (pick_proc = proc_queue_h[PRIV0];
			pick_proc;pick_proc = pick_proc->next){
				if (pick_proc->msg){
					break;
				}
	}

	return pick_proc;
}

struct proc* user_proc_pick(int priv){
	struct proc *pick_proc = NULL;

	for (pick_proc = proc_queue_h[priv];
			;pick_proc = pick_proc->next){
				if (pick_proc){
					break;
				}
	}
	return pick_proc;
}

struct proc* suspend_proc_pick(int priv){
	struct proc *pick_proc = NULL;
	return pick_proc;
}

struct proc* dummy_proc_pick(int priv){
	/* avoid warning */
	priv = priv;
	return &(proc[PROC_IDLE]);
}


#define priv0_pick	server_proc_pick
#define priv1_pick  user_proc_pick
#define	priv2_pick	user_proc_pick
#define priv3_pick	user_proc_pick
#define	priv4_pick  user_proc_pick
#define	priv5_pick  user_proc_pick
#define priv6_pick  user_proc_pick
#define priv7_pick  user_proc_pick


typedef struct proc* (*priv_pick)(int priv);

PRIVATE priv_pick pick_proc_by_priv_table[]={
	priv0_pick,
	priv1_pick,
	priv2_pick,
	priv3_pick,
	priv4_pick,
	priv5_pick,
	priv6_pick,
	priv7_pick
};

static struct proc *pick_proc_by_queue(void){
	struct proc *pick_proc = NULL;
	int priv;

	for (priv = PRIV0 ; priv < PRIV_MAX; priv++){
		if ((pick_proc = pick_proc_by_priv_table[priv](priv))){
			break;
		}
	}

	return pick_proc;
}

 /*
  *  pick a runnable process from the processes queue 
  */
int sched(struct proc *candidate_proc){
	struct proc *pick_proc = NULL;

	if ((pick_proc = candidate_proc)){
		/* do nothing */
	}else if ((pick_proc = pick_proc_by_queue())){
		/* do nothing */
	}

	if(pick_proc == cur_proc){
		return 0;
	}

	do_switch(pick_proc);
	
	return 0;
}

